package databook;

import databook.controller.Props;
import databook.controller.PropertyListener;
import databook.controller.PropertyEvent;
import databook.controller.FilterCheckBox;
import databook.controller.PropertyCheckBox;
import databook.controller.DBRangeSlider;

import databook.filter.FilterListener;
import databook.filter.FilterEvent;
import databook.filter.DataFilter;
import databook.util.MajorMap;
import databook.util.FilterHash;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Component;
import java.awt.event.*;
import java.util.Vector;
import java.util.Arrays;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;

import prefuse.util.ui.JRangeSlider;
import prefuse.util.ui.JValueSlider;
import prefuse.util.ui.JToggleGroup;
import prefuse.Display;
import prefuse.visual.VisualItem;

public class ControlPanel extends JPanel implements PropertyListener {
    //private FilterHash filterMap;
    private Vector<FilterListener> filterListeners;
    
    private NodeVisualization nodeViz;
    private WeightTree nodes;

    private int maxEdges = 100;
    
    private String[] stacks = {"GENDER","GRADUATED","RACE"}; 

    public ControlPanel(WeightTree nodes) {
        this(nodes,10000);
    }
    
    public ControlPanel(WeightTree nodes,int maxEdges) {
        this.nodes = nodes;
        this.maxEdges = maxEdges;
        //filterMap = new FilterHash();
        //setDateRange();
        
        nodeViz = new NodeVisualization(stacks);
        //nodeViz.setYears(Props.getInt(Props.START_YEAR),Props.getInt(Props.END_YEAR),Props.getString(Props.START_TERM),Props.getString(Props.END_TERM));

        initComponents();
        
        Props.addListener(Props.SELECTED_ITEM,this);
        Props.addListener(Props.CLICKED_EDGE,this);
        /*Props.addListener(Props.CURRENT_RANGE_MIN,new PropertyListener() {
            public void propertyChanged(PropertyEvent evt) {
                if(((Integer)evt.value).intValue() != yearDoubleSlider.getLowValue()) {
                    yearDoubleSlider.setLowValue(((Integer)evt.value).intValue());
                }
            }
        });
        
        Props.addListener(Props.CURRENT_RANGE_MAX,new PropertyListener() {
            public void propertyChanged(PropertyEvent evt) {
                if(((Integer)evt.value).intValue() != yearDoubleSlider.getHighValue()) {
                    yearDoubleSlider.setHighValue(((Integer)evt.value).intValue());
                }
            }
        });/**/
    }
    
    private void setDateRange() {
        /*
        System.out.println("Should not be seen");
        try {
            String[] values = (String[])nodes.getValues("TERM").toArray(new String[0]);
            Arrays.sort(values);
            Props.set(Props.START_TERM,values[0]);
            Props.set(Props.START_YEAR,Integer.parseInt(values[0].substring(0,4)));
            Props.set(Props.END_TERM,values[values.length-1]);
            Props.set(Props.END_YEAR,Integer.parseInt(values[values.length-1].substring(0,4)));
            Props.setDefault(Props.CURRENT_RANGE_MIN,Props.getInt(Props.START_YEAR));
            Props.setDefault(Props.CURRENT_RANGE_MAX,Props.getInt(Props.END_YEAR));
        } catch (Exception e) {
            System.err.println("Something went wrong that shouldn't have: " + e);
        }/**/
        
    }

    private void initComponents() {
          tabbedPanel = new JTabbedPane();
          
          initFilterTab();
          initGraphTab();
          initLegendTab();
    //      initSaveTab();

          tabbedPanel.addTab("Filtering", filterTab);
          tabbedPanel.addTab("Details",graphTab);
          tabbedPanel.addTab("Legend",legendTab);

      //    tabbedPanel.addTab("Save", saveTab);

          
          GroupLayout layout = new GroupLayout(this);
          this.setLayout(layout);
          layout.setHorizontalGroup(
              layout.createParallelGroup(GroupLayout.Alignment.LEADING)
              .addComponent(tabbedPanel, GroupLayout.DEFAULT_SIZE, 250, Short.MAX_VALUE)
          );
          layout.setVerticalGroup(
              layout.createParallelGroup(GroupLayout.Alignment.LEADING)
              .addComponent(tabbedPanel, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 580, Short.MAX_VALUE)
          );
    }

    private void initLegendTab() {
        legendTab = new JPanel();
        legendTab.add(Props.getLegend());
    }
    
    private void initGraphTab() {
        int yLocation = 0;
        GridBagConstraints gridBagConstraints;
        
        graphTab = new JPanel();
        graphTab.setLayout(new GridBagLayout());
        
        majorNameLabel = new JLabel("--Selected--");
        yLocation += 2;        
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = yLocation;
        gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 0);        
        gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagConstraints.anchor = GridBagConstraints.NORTH;
        graphTab.add(majorNameLabel,gridBagConstraints);
        
        Display[] displays = nodeViz.getDisplays();
        for (int i = 0; i < displays.length; i++) {
            JPanel dpanel = new JPanel();
            dpanel.setBorder(BorderFactory.createTitledBorder(camelCase(stacks[i])));
            dpanel.add(displays[i]);
            
            yLocation += 1;        
            gridBagConstraints = new GridBagConstraints();
            gridBagConstraints.gridx = 0;
            gridBagConstraints.gridy = yLocation;
            gridBagConstraints.insets = new java.awt.Insets(5, 5, 0, 0);        
            //gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
            gridBagConstraints.anchor = GridBagConstraints.NORTH;
            graphTab.add(dpanel,gridBagConstraints);
            
            gridBagConstraints = new GridBagConstraints();
            gridBagConstraints.gridx = 1;
            gridBagConstraints.gridy = yLocation;
            gridBagConstraints.insets = new java.awt.Insets(5, 5, 0, 0);        
            gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
            gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
            graphTab.add(Props.getLegend(stacks[i]),gridBagConstraints);
            //graphTab.add(displays[i],gridBagConstraints);
            //displays[i].setBorder(BorderFactory.createTitledBorder(camelCase(stacks[i])));
        }        
    }
    
    private String camelCase(String name) {
        return name.substring(0,1).toUpperCase() + name.substring(1).toLowerCase();
    }

    private void initFilterTab() {
    	int yLocation = 0;
        GridBagConstraints gridBagConstraints;

        filterTab = new JPanel();
        
        yearGroup = new JPanel();
        yearLabel = new JLabel();
        //yearDoubleSlider = new JRangeSlider(Props.getInt(Props.START_YEAR),Props.getInt(Props.END_YEAR), Props.getInt(Props.START_YEAR),Props.getInt(Props.END_YEAR), JRangeSlider.HORIZONTAL);
        yearDoubleSlider = new DBRangeSlider();
        yearMax = new JLabel();
        yearMin = new JLabel();
        yearSliderContainer = new JPanel();
        
        threshholdGroup = new JPanel();
        //threshholdLabel = new JLabel("Edge Threshhold");
        threshholdSlider = new JValueSlider("Edge Threshhold:",Props.getInt(Props.EDGE_THRESHHOLD,0),Props.getInt(Props.MAX_THRESHHOLD,100),0);
        threshholdSlider.setTextFieldSize(3);
        threshholdContainer = new JPanel();
        
        genderGroup = new JPanel();
        genderLabel = new JLabel();
        genderFemale = new FilterCheckBox("Female","GENDER","F");
        genderMale = new FilterCheckBox("Male","GENDER","M");
        
        checkboxTree = new JTree(nodes);
        majorGroup = new JScrollPane(checkboxTree);
        majorLabel = new JLabel();
        //majorCheckPane = new JPanel();
        
        gradGroup = new JPanel();
        gradLabel = new JLabel();
        gradFalse = new FilterCheckBox("No","GRADUATED","N");
        gradTrue = new FilterCheckBox("Yes","GRADUATED","Y");
        gradNotYet = new FilterCheckBox("Not Yet","GRADUATED","Not Yet");
        
        normalize = new PropertyCheckBox("Normalize",Props.NORMALIZE_SIZE,true);
        highlightIn = new PropertyCheckBox("In Edges",Props.HIGHLIGHT_IN,true);
        highlightOut = new PropertyCheckBox("Out Edges",Props.HIGHLIGHT_OUT,true);
        autoLayout = new PropertyCheckBox("Auto Layout Nodes",Props.AUTO_LAYOUT,true);
        
        percentToggle = new JToggleGroup(JToggleGroup.RADIO,new String[] {"Number","Percent In","Percent Out"});
        
        //raceViz = raceDisplay();

        filterTab.setLayout(new java.awt.GridBagLayout());
        
        
        majorLabel.setText("Majors");
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = yLocation;
        gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 0);
        gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagConstraints.anchor = GridBagConstraints.WEST;
        filterTab.add(majorLabel, gridBagConstraints);

        //initMajors();

        //majorGroup.setViewportView(majorCheckPane);
        //JTree tree = new JTree(nodes);
        checkboxTree.setRootVisible(false);
        checkboxTree.setShowsRootHandles(true);
        TreeCellRenderer render = new TreeCellRenderer() {
            public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
                //System.out.println(((WeightTree)value).getCheckBox());
                return ((WeightTree)value).getCheckBox();
            } 
        };
        checkboxTree.setCellRenderer(render);
        checkboxTree.addTreeSelectionListener(new TreeSelectionListener() {
            public void valueChanged(TreeSelectionEvent e) {
                if (e.isAddedPath()) {
                    //System.out.println("Here");
                    ((WeightTree)e.getPath().getLastPathComponent()).select();
                    ((JTree)e.getSource()).clearSelection();
                    ((JTree)e.getSource()).repaint();
                }
            }
        });
        
        checkboxTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
        majorGroup.setMinimumSize(new Dimension(350,325));
        majorGroup.setPreferredSize(new Dimension(350,350));


        yLocation += 2;
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = yLocation;
        gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 0);
        gridBagConstraints.anchor = GridBagConstraints.WEST;
        filterTab.add(majorGroup, gridBagConstraints);
        
        
        gradGroup.setLayout(new BoxLayout(gradGroup, BoxLayout.LINE_AXIS));
        gradLabel.setText("Graduated: ");
        gradGroup.add(gradLabel);  
        gradGroup.add(gradTrue);
        gradGroup.add(gradFalse);
        gradGroup.add(gradNotYet);
        
        yLocation += 2;
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = yLocation;
        gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 0);        
        gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagConstraints.anchor = GridBagConstraints.WEST;
        filterTab.add(gradGroup, gridBagConstraints);


        genderGroup.setLayout(new BoxLayout(genderGroup, BoxLayout.LINE_AXIS));        
        genderLabel.setText("Gender: ");
        genderGroup.add(genderLabel);
        genderGroup.add(genderFemale);
        genderGroup.add(genderMale);

        yLocation += 1;
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = yLocation;
        gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagConstraints.anchor = GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(3, 10, 3, 0);
        filterTab.add(genderGroup, gridBagConstraints);

        yearGroup.setLayout(new BoxLayout(yearGroup, BoxLayout.LINE_AXIS));
        yearLabel.setText("Terms:");
        yearLabel.setLabelFor(yearDoubleSlider);
        yearGroup.add(yearLabel);
        //yearGroup.add(Box.createRigidArea(new Dimension(5,0)));
        //yearSliderContainer.setLayout(new BoxLayout(yearSliderContainer, BoxLayout.LINE_AXIS));
        //yearSliderContainer.setAlignmentX(yearGroup.LEFT_ALIGNMENT);
        //yearSliderContainer.setBorder(BorderFactory.createLineBorder(java.awt.Color.RED));
        
        //yearMin.setText(String.valueOf(yearDoubleSlider.getMinimum()));
        //yearGroup.add(yearMin);
        
        /*yearDoubleSlider.addMouseListener(new MouseAdapter() {
                public void mouseReleased(MouseEvent e) {
                    yearSliderCommit();
                }
        });
        yearDoubleSlider.addChangeListener(new javax.swing.event.ChangeListener() {
                public void stateChanged(ChangeEvent e) {
                        yearSliderChange();
                }
        });/**/
        yearDoubleSlider.setMinimumSize(new Dimension(350, yearDoubleSlider.getHeight()));
        //yearSliderContainer.add(yearDoubleSlider);
        //yearSliderContainer.setMinimumSize(new Dimension(350, yearDoubleSlider.getHeight()+20));
        //yearGroup.add(yearSliderContainer);

        //yearMax.setText(String.valueOf(yearDoubleSlider.getMaximum()));
        //yearSliderContainer.add(yearMax);
        
        yearGroup.add(yearDoubleSlider);

        yLocation += 2;
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = yLocation;
        gridBagConstraints.insets = new java.awt.Insets(10, 10, 0, 0);        
        gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagConstraints.anchor = GridBagConstraints.WEST;
        //filterTab.add(new DBRangeSlider(), gridBagConstraints);
        filterTab.add(yearGroup, gridBagConstraints);
        
        // Threshhold Slider
        threshholdGroup.setLayout(new BoxLayout(yearGroup, BoxLayout.LINE_AXIS));
        threshholdSlider.setSize(350, threshholdSlider.getHeight());
        threshholdContainer.add(threshholdSlider);
        threshholdContainer.setMinimumSize(new Dimension(350, threshholdSlider.getHeight() + 30));
        yLocation += 2;
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = yLocation;
        gridBagConstraints.insets = new java.awt.Insets(10, 10, 0, 0);        
        gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagConstraints.anchor = GridBagConstraints.WEST;
        filterTab.add(threshholdContainer, gridBagConstraints);
        threshholdSlider.addChangeListener(new javax.swing.event.ChangeListener() {
			public void stateChanged(ChangeEvent e) {
                            Props.set(Props.EDGE_THRESHHOLD,((JValueSlider)e.getSource()).getValue());
                        }});
        Props.addListener(Props.EDGE_THRESHHOLD,new PropertyListener() {
                        public void propertyChanged(PropertyEvent evt) {
                            threshholdSlider.setValue(((Integer)evt.value).intValue());
                        }
        });
        
        Props.addListener(Props.MAX_THRESHHOLD,new PropertyListener() {
                        public void propertyChanged(PropertyEvent evt) {
                            threshholdSlider.setMax(((Integer)evt.value).intValue());
                        }
        });

        yLocation += 2;        
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = yLocation;
        gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 0);        
        gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagConstraints.anchor = GridBagConstraints.WEST;
        filterTab.add(normalize, gridBagConstraints);
        
        JPanel highlights = new JPanel(new FlowLayout());
        JLabel neighbors = new JLabel("Highlight Neighbors");
        highlights.add(neighbors);
        highlights.add(highlightIn);
        highlights.add(highlightOut);
        
        yLocation += 2;        
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = yLocation;
        gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 0);        
        gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagConstraints.anchor = GridBagConstraints.WEST;
        filterTab.add(highlights, gridBagConstraints);
        
        yLocation += 2;        
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = yLocation;
        gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 0);        
        gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagConstraints.anchor = GridBagConstraints.WEST;
        filterTab.add(autoLayout, gridBagConstraints);
        filterTab.add(percentToggle, gridBagConstraints);
        percentToggle.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        percentToggle.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent evt) {
                int ind = ((ListSelectionModel)evt.getSource()).getLeadSelectionIndex();
                if (ind == 0) {
                    Props.set(Props.PERCENT_OUT,false);
                    Props.set(Props.PERCENT_IN,false);
                } else if (ind == 1) {
                    Props.set(Props.PERCENT_OUT,false);
                    Props.set(Props.PERCENT_IN,true);
                } else {
                    Props.set(Props.PERCENT_OUT,true);
                    Props.set(Props.PERCENT_IN,false);
                }
            }
        });
        if (Props.getBoolean(Props.PERCENT_IN))
            percentToggle.getSelectionModel().addSelectionInterval(1,1);
        if (Props.getBoolean(Props.PERCENT_IN))
            percentToggle.getSelectionModel().addSelectionInterval(2,2);
        else
            percentToggle.getSelectionModel().addSelectionInterval(0,0);
                
        yLocation += 2;        
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = yLocation;
        gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 0);        
        gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagConstraints.anchor = GridBagConstraints.WEST;
        filterTab.add(autoLayout, gridBagConstraints);
    }
    
/*    private void yearSliderChange() {
    	yearMin.setText(String.valueOf(yearDoubleSlider.getLowValue()));
    	yearMax.setText(String.valueOf(yearDoubleSlider.getHighValue()));
    }
    
    private void yearSliderCommit() {
        
        // For the filter, go through each possible year and set the filter value
        // This might not be effecient.  Just trying it out for now.
        System.out.println("Commit");
        for (int i = yearDoubleSlider.getMinimum(); i <= yearDoubleSlider.getMaximum(); i++) {
            if (i >= yearDoubleSlider.getLowValue() && i <= yearDoubleSlider.getHighValue()) {
                Props.setFilter("TERM",i + "-1",true,false);
                Props.setFilter("TERM",i + "-2",true,false);
            } else {
                Props.setFilter("TERM",i + "-1",false,false);
                Props.setFilter("TERM",i + "-2",false,false);
            }
        }
        Props.set(Props.CURRENT_RANGE_MIN,yearDoubleSlider.getLowValue());
        Props.set(Props.CURRENT_RANGE_MAX,yearDoubleSlider.getHighValue());
        // Only notify listeners at the end.  This drastically speeds up the slider
        //notifyFilterListeners(new FilterEvent("TERM","",true));
        nodeViz.setYears(yearDoubleSlider.getLowValue(), yearDoubleSlider.getHighValue(),Props.getString(Props.START_TERM),Props.getString(Props.END_TERM));
    }/**/
    
    public void propertyChanged(PropertyEvent evt) {
        if (evt.value != null) {
            majorNameLabel.setText(DatabookViz.getLabel((VisualItem)evt.value));
        }
    }
        
    private JPanel filterTab;
    private JPanel graphTab;
    private JPanel legendTab;
    
    private JLabel majorNameLabel;
    
    private JPanel genderGroup;
    private JLabel genderLabel;
    private FilterCheckBox genderFemale;
    private FilterCheckBox genderMale;

    private JScrollPane majorGroup;
    private JTree checkboxTree;
    private JLabel majorLabel;
    
    private JPanel gradGroup;
    private JLabel gradLabel;
    private FilterCheckBox gradTrue;
    private FilterCheckBox gradFalse; 
    private FilterCheckBox gradNotYet;
    
    private JPanel threshholdGroup;
    private JLabel threshholdLabel;
    private JPanel threshholdContainer;
    private JValueSlider threshholdSlider;
    
    private PropertyCheckBox normalize;
    private PropertyCheckBox highlightIn;
    private PropertyCheckBox highlightOut;
    private PropertyCheckBox autoLayout;
    
    private JPanel yearGroup;
    private JPanel yearSliderContainer;
    private JLabel yearLabel;
    private JLabel yearMin;
    private JLabel yearMax;
    private DBRangeSlider yearDoubleSlider;
    

    private JToggleGroup percentToggle;
    
    
    private JTabbedPane tabbedPanel;
}
